from sys import argv
from OpenGL.GL import *
from OpenGL.GLU import *
from OpenGL.GLUT import *

# 第三周 第一节 中点法画圆


class MyPyOpenGLTest:
    # 初始化OpenGL环境，指定显示模式以及用于绘图的函数
    def __init__(self, width=640, height=480,
                 title='中点算法画圆'.encode('gbk')):
        glutInit(argv)
        # 使用RGBA颜色、双缓冲
        glutInitDisplayMode(GLUT_RGBA | GLUT_DOUBLE | GLUT_DEPTH)
        # 设置图形窗口初始大小和位置，然后创建图形窗口，顺序不能变
        glutInitWindowSize(width, height)
        glutInitWindowPosition(400, 200)
        glutCreateWindow(title)
        # 指定绘制图形时执行的方法
        glutDisplayFunc(self.draw)
        # 指定调整窗口大小时执行的方法
        glutReshapeFunc(self.reshape)

        # 指定鼠标按下与抬起执行的方法
        glutMouseFunc(self.mouse_downup)

        # 指定鼠标移动时执行的方法
        glutMotionFunc(self.mouse_move)

        glMatrixMode(GL_MODELVIEW)
        glLoadIdentity()

        #
        self.t1, self.t2 = None, None

        # 本次绘制直线的起点和重点坐标
        self.x_start, self.y_start = None, None
        self.x_end, self.y_end = None, None

        #False
        self.can_draw = False

        # 定义裁剪窗口
        # 左下角x坐标、左下角y坐标、右上角x坐标、右上角y坐标
        self.rect = (200, 150, 400, 250)

        # 左右上下编码
        self.left = 0b0001
        self.right = 0b0010
        self.bottom = 0b0100
        self.top = 0b1000



        # 指定系统空闲时执行的方法
        # glutIdleFunc(self.draw)
        # 进一步初始化，完成个性化设置
        # self.InitGL(width, height)

    # 根据特定的需要，进一步完成OpenGL的初始化
    def InitGL(self, width, height):
        # 初始化窗口背景为白色
        glClearColor(1.0, 1.0, 1.0, 1.0)
        # 切换到透视投影矩阵
        glMatrixMode(GL_PROJECTION)
        # 加载单位矩阵，重置
        glLoadIdentity()
        gluOrtho2D(0, width, 0, height)
        # 切换到模型观察矩阵
        glMatrixMode(GL_MODELVIEW)
        glLoadIdentity()

    # 调整图形窗口大小时执行的方法
    def reshape(self, w, h):

        # 设置视口/视区的左下角x、y坐标以及窗口宽度和高度
        # 视口是最终用来显示图形的区域
        glViewport(0, 0, w, h)
        # 切换到透视投影矩阵
        glMatrixMode(GL_PROJECTION)
        glLoadIdentity()
        # 设置世界窗口的左下角x坐标、右上角x坐标、左下角y坐标、右上角y坐标
        # 这是需要显示到视口的图形区域
        # gluOrtho2D(0, w, 0, h)
        # 设置窗口
        gluOrtho2D(0, w, h, 0)
        # 修改为下面的大小可以看到直线段被放大后像素离散的状态

        # 切换到模型观察矩阵
        glMatrixMode(GL_MODELVIEW)
        glLoadIdentity()

    def compute_t(self, lk, mk):
        flag = True
        if lk == 0:
            if mk < 0:
                flag = False
        else:
            tk = mk / lk
            if lk < 0:
                if tk > self.t2:
                    flag = False
                elif tk > self.t1:
                    self.t1 = tk
            else:
                if tk < self.t1:
                    flag = False
                elif tk < self.t2:
                    self.t2 = tk
        return flag




    def clip(self):

        # 根据self.rect 定义的窗口对直线进行裁剪
        # 直线起点与中点编码
        self.can_draw = False
        self.t1, self.t2 = 0, 1
        dx = self.x_end - self.x_start
        if (self.compute_t(-dx, self.x_start-self.rect[0]) and
            self.compute_t(dx, self.rect[2]-self.x_start)):
            dy = self.y_end - self.y_start
            if(self.compute_t(-dy, self.y_start-self.rect[1]) and
               self.compute_t(dy, self.rect[3]-self.y_start)):
                if self.t2 < 1:
                    self.x_end = self.x_start + self.t2 * dx
                    self.y_end = self.y_start + self.t2 * dy
                if self.t1 > 0:
                    self.x_start = self.x_start + self.t1 * dx
                    self.y_start = self.y_start + self.t1 * dy
                self.can_draw = True





    def mouse_downup(self, button, state, x, y):
        if button != GLUT_LEFT_BUTTON:
            # 只响应鼠标左键，其他按键直接返回
            return
        if state == GLUT_DOWN:
            # 鼠标按下，设置直线的起点坐标，以窗口左上角为坐标原点
            self.x_start, self.y_start = x, y
            self.x_end, self.y_end = None, None
        elif state == GLUT_UP:
            # 鼠标抬起，结束绘制直线，然后裁剪并强制刷新屏幕
            self.clip()
            glutPostRedisplay()


    def mouse_move(self, x, y):
        # 设置直线中点坐标
        # 鼠标当前位置坐标x、y是以窗口左上角为坐标原点的偏移量
        # 动态修改直线的中点坐标位置
        self.x_end, self.y_end = x, y

        self.can_draw = True
        glutPostRedisplay()

    # 自己的绘图方法，本程序的关键
    def draw(self):
        # 初始化窗口背景为白色
        glClear(GL_COLOR_BUFFER_BIT)

        glClearColor(1.0, 1.0, 1.0, 1.0)
        # 每次绘制图形之前清除颜色缓冲区和深度缓冲区中的信息
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT)
        # 黑色
        glColor3f(0, 0, 0)
        # 切换到模型观察矩阵，才能正确绘制图形
        glMatrixMode(GL_MODELVIEW)
        glLoadIdentity()
        glTranslatef(0, 0, 0)

        glPolygonMode(GL_FRONT_AND_BACK, GL_LINE)
        glLineWidth(3)

        # 序列解包
        glRectf(*self.rect)
        glLineWidth(1)

        if self.can_draw:
            glBegin(GL_LINES)
            glVertex2f(self.x_start, self.y_start)
            glVertex2f(self.x_end, self.y_end)
            glEnd()

        # self.draw_circle_Mid(0, 0, 90, (0, 1, 0))
        glutSwapBuffers()

    # 消息主循环
    def mainloop(self):
        glutMainLoop()

if __name__ == '__main__':
    # 创建窗口对象，启动消息主循环
    MyPyOpenGLTest().mainloop()
